


namespace SharpTalk.Core.Services.ServiceAgents
{
    using System;
    using System.ServiceModel;
    using Contracts.Server;
    using Interfaces;

    public abstract class ServiceAgentBase<
        TContract,
        TCreateRequest, TCreateResponse,
        TFindRequest, TFindResponse,
        TUpdateRequest, TUpdateResponse,
        TDeleteRequest, TDeleteResponse>
        : ClientBase<TContract> where TContract : class, IRequestServiceBase<
                TCreateRequest, TCreateResponse,
                TFindRequest, TFindResponse,
                TUpdateRequest, TUpdateResponse,
                TDeleteRequest, TDeleteResponse> 
        where TCreateResponse : IErrorDetails, new()
        where TFindResponse : IErrorDetails, new()
        where TUpdateResponse : IErrorDetails, new()
        where TDeleteResponse : IErrorDetails, new()
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ServiceAgentBase" />
        ///   class using the configuration information specified in the application configuration file by <paramref name="endpointConfigurationName"/>. 
        /// </summary>
        /// <param name="endpointConfigurationName">The name of the endpoint in the application configuration file.</param><exception cref="T:System.ArgumentNullException">The specified endpoint information is null.</exception><exception cref="T:System.InvalidOperationException">The endpoint cannot be found or the endpoint contract is not valid.</exception>
        protected ServiceAgentBase(string endpointConfigurationName) 
            : base(endpointConfigurationName)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ServiceAgentBase"/> class using the configuration information specified in the application configuration file by <paramref name="endpointConfigurationName"/>. 
        /// </summary>
        /// <param name="endpointConfigurationName">The name of the endpoint in the application configuration file.</param>
        /// <param name="remoteAddress"></param>
        /// <exception cref="T:System.ArgumentNullException">The specified endpoint information is null.</exception><exception cref="T:System.InvalidOperationException">The endpoint cannot be found or the endpoint contract is not valid.</exception>
        protected ServiceAgentBase(string endpointConfigurationName, EndpointAddress remoteAddress) 
            : base(endpointConfigurationName, remoteAddress)
        {
        }

        public virtual IAsyncResult BeginCreate(TCreateRequest request, AsyncCallback callback, object state)
        {
            return base.Channel.BeginCreate(request, callback, state);
        }

        public virtual TCreateResponse EndCreate(IAsyncResult result)
        {
            try
            {
                return base.Channel.EndCreate(result);
            }
            catch (Exception exp)
            {
                return new TCreateResponse(){ Error = new ErrorDetails(exp)  };
            }
        }

        public virtual IAsyncResult BeginFind(TFindRequest request, AsyncCallback callback, object state)
        {
            return base.Channel.BeginFind(request, callback, state);
        }

        public virtual TFindResponse EndFind(IAsyncResult result)
        {
            try
            {
                return base.Channel.EndFind(result);
            }
            catch (Exception exp)
            {
                return new TFindResponse(){ Error = new ErrorDetails(exp) };
            }
        }

        public virtual IAsyncResult BeginUpdate(TUpdateRequest request, AsyncCallback callback, object state)
        {
            return base.Channel.BeginUpdate(request, callback, state);
        }

        public virtual TUpdateResponse EndUpdate(IAsyncResult result)
        {
            try
            {
                return base.Channel.EndUpdate(result);
            }
            catch (Exception exp)
            {
                return new TUpdateResponse(){ Error = new ErrorDetails(exp)};
            }
        }

        public virtual IAsyncResult BeginDelete(TDeleteRequest request, AsyncCallback callback, object state)
        {
            return base.Channel.BeginDelete(request, callback, state);
        }

        public virtual TDeleteResponse EndDelete(IAsyncResult result)
        {
            try
            {
                return base.Channel.EndDelete(result);
            }
            catch (Exception exp)
            {
                return new TDeleteResponse(){ Error = new ErrorDetails(exp) };
            }
        }
    }
}